package lesbonsamis;

import java.util.Arrays;

class AB {

	int[] A; // vecteur d'état
	int[][] B; // matrice de transaction

	/*
	 * Constructeur initialise A avec paramètre Adep initialise B à 0
	 */
	public AB(int[] Adep) {
		int taille = Adep.length;

		this.A = new int[taille];
		System.arraycopy(Adep, 0, this.A, 0, taille);

		this.B = new int[taille][taille];
		for (int i = 0; i < taille; i++) {
			for (int j = 0; j < taille; j++) {
				B[i][j] = 0;
			}
		}
	}

	/*
	 * Constructeur par copie copie ABdep dans AB
	 */
	public AB(AB ABdep) {
		int taille = ABdep.A.length;

		this.A = new int[taille];
		System.arraycopy(ABdep.A, 0, this.A, 0, taille);

		this.B = new int[taille][taille];
		for (int i = 0; i < taille; i++) {
			System.arraycopy(ABdep.B[i], 0, this.B[i], 0, taille);
		}
	}

	/*
	 * Affiche A et B
	 */
	public void afficher() {
		int taille = this.A.length;

		System.out.print("A: ");
		for (int i = 0; i < taille; i++) {
			System.out.print(this.A[i] + " ");
		}
		System.out.print("\n");

		System.out.println("B: ");
		for (int i = 0; i < taille; i++) {
			for (int j = 0; j < taille; j++) {
				System.out.print(this.B[i][j] + " ");
			}
			System.out.print("\n");
		}
		System.out.print("\n");
	}

	/*
	 * Affiche la suite de transactions
	 */
	public void verifier() {
		int taille = this.A.length;

		System.out.print("A: ");
		for (int i = 0; i < taille; i++) {
			System.out.print(this.A[i] + " ");
		}
		System.out.print("\n");

		for (int i = 0; i < taille; i++) {
			for (int j = 0; j < taille; j++) {
				if (B[i][j] != 0) {
					System.out.println("transaction = " + this.B[i][j]);

					this.A[i] -= this.B[i][j];
					this.A[j] += this.B[i][j];

					System.out.print("A: ");
					for (int x = 0; x < taille; x++) {
						System.out.print(this.A[x] + " ");
					}
					System.out.print("\n");
				}
			}
		}
	}

	/*
	 * Trasnsaction de i vers j ajoute la transaction à Bij ajoute la valeur de
	 * Ai à Aj positionne Ai à 0
	 */
	public void transaction(int i, int j) {
		this.B[i][j] += this.A[i];
		this.A[j] += this.A[i];
		this.A[i] = 0;
	}

	/*
	 * Transaction de i vers j
	 */
	public void transaction(int de, int vers, int val) {
		this.B[de][vers] += val;
		this.A[vers] += val;
		this.A[de] -= val;
	}

	/*
	 * Retourne TRUE si A est null, FALSE sinon
	 */
	public boolean nulA() {
		boolean retour = true;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			if (this.A[x] != 0)
				retour = false;
		}
		return retour;
	}

	/*
	 * Retourne TRUE si Ai est null, FALSE sinon
	 */
	public boolean nulA(int i) {
		boolean retour = false;
		if (this.A[i] == 0) {
			retour = true;
		}
		return retour;
	}

	/*
	 * Retourne TRUE si Ai est positif, FALSE sinon
	 */
	public boolean posA(int i) {
		boolean retour = false;
		if (this.A[i] > 0) {
			retour = true;
		}
		return retour;
	}

	/*
	 * Retourne TRUE si Ai est négatif, FALSE sinon
	 */
	public boolean negA(int i) {
		boolean retour = false;
		if (this.A[i] < 0) {
			retour = true;
		}
		return retour;
	}

	/*
	 * Retourne TRUE si Ai est le max, FALSE sinon
	 */
	public boolean maxA(int i) {
		boolean retour = true;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			if (this.A[i] < this.A[x]) {
				retour = false;
			}
		}
		return retour;
	}

	/*
	 * Retourne TRUE si Ai est le min, FALSE sinon
	 */
	public boolean minA(int i) {
		boolean retour = true;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			if (this.A[i] > this.A[x]) {
				retour = false;
			}
		}
		return retour;
	}

	/*
	 * Retourne la position du min de A
	 */
	public int minA() {
		int retour = 0;
		int max = Integer.MAX_VALUE;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			if (this.A[x] < max) {
				max = this.A[x];
				retour = x;
			}
		}
		return retour;
	}

	/*
	 * Retourne la position du max de A
	 */
	public int maxA() {
		int retour = 0;
		int min = Integer.MIN_VALUE;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			if (this.A[x] > min) {
				min = this.A[x];
				retour = x;
			}
		}
		return retour;
	}

	/*
	 * Retourne TRUE si Ai est le max absolu, FALSE sinon
	 */
	public boolean maxAbsA(int i) {
		boolean retour = true;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			if (Math.abs(this.A[i]) < Math.abs(this.A[x])) {
				retour = false;
			}
		}
		return retour;
	}

	/*
	 * Retourne TRUE si Ai est le min absolu et != 0, FALSE sinon
	 */
	public boolean minAbsA(int i) {
		boolean retour = true;
		int taille = this.A.length;

		if (this.A[i] == 0) {
			retour = false;
		}

		for (int x = 0; x < taille; x++) {
			if ((this.A[x] != 0) && (Math.abs(this.A[i]) > Math.abs(this.A[x]))) {
				retour = false;
			}
		}
		return retour;
	}

	public boolean minDiffA(int i, int j) {
		boolean retour = true;
		int taille = this.A.length;
		int[][] diff = new int[taille][taille];

		for (int x = 0; x < taille; x++) {
			for (int y = 0; y < taille; y++) {
				diff[x][y] = Math.abs(this.A[x] + this.A[y]);
			}
		}

		for (int x = 0; x < taille; x++) {
			for (int y = 0; y < taille; y++) {
				if ((this.A[x] != this.A[y]) && (this.A[x] != 0)
						&& (this.A[y] != 0) && (diff[i][j] > diff[x][y])) {
					retour = false;
				}
			}
		}
		return retour;
	}

	/*
	 * Compte les transactions dans B transaction : Bij != 0
	 */
	public int nbTrans() {
		int somme = 0;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			for (int y = 0; y < taille; y++) {
				if (this.B[x][y] != 0) {
					somme++;
				}
			}
		}
		return somme;
	}

	/*
	 * somme des valeurs absolues des transactions (B)
	 */
	public int somB() {
		int somme = 0;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			for (int y = 0; y < taille; y++) {
				somme += Math.abs(this.B[x][y]);
			}
		}
		return somme;
	}

	/*
	 * somme des valeurs absolues des états (A)
	 */
	public int somA() {
		int somme = 0;
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			somme += Math.abs(this.A[x]);
		}
		return somme;
	}

	/*
	 * rend la matrice de transactions (B) positive transaction Bij équivalent
	 * à -Bji
	 */
	public void reduire() {
		int taille = this.A.length;

		for (int x = 0; x < taille; x++) {
			for (int y = 0; y < taille; y++) {
				if (this.B[x][y] < 0) {
					this.B[y][x] -= this.B[x][y];
					this.B[x][y] = 0;
				}
			}
		}
	}

	@Override
	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (!(o instanceof AB))
			return false;
		AB ab = (AB) o;

		int taille = this.A.length;
		for (int x = 0; x < taille; x++) {
			for (int y = 0; y < taille; y++) {
				if (this.B[x][y] != ab.B[x][y]) {
					return false;
				}
			}
		}
		return true;
	}

	@Override
	public int hashCode() {
		int hash = 7;
		hash = 47 * hash + Arrays.hashCode(this.A);
		hash = 47 * hash + Arrays.deepHashCode(this.B);
		return hash;
	}
}
